﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using SeizyUtils.AppCode.Common.Data.Model.Bean;
using SeizyUtils.Common.Utilities;
using SeizyUtils.Bean;
using SeizyUtils.Common.Data;

namespace SeizyUtils
{
    /// <summary>
    /// データモデルおよびカラム定義情報を管理するクラスです。
    /// 全てのIDefinition、IColumnはここで生成されます。
    /// 
    /// このクラスは、基本的にフレームワークの内部で利用されます。
    /// </summary>
    class DefinitionManager
    {

        private static readonly Dictionary<string, SeizyUtils.Common.Data.IColumn> _columnMapping = new Dictionary<string, IColumn>();

        private static readonly Dictionary<string, IDefinition> _definitionMapping = new Dictionary<string, IDefinition>(); 

        static DefinitionManager()
        {
            // カラム情報を読み込みます。
            try
            {
                createDefinition(typeof(DeliveryResult));
                createDefinition(typeof(PickingReceive));
                createDefinition(typeof(PickingResult));
                createDefinition(typeof(PostStockReceive));
                createDefinition(typeof(PostStockResult));
                createDefinition(typeof(PostStockUpdate));
                createDefinition(typeof(WarehouseStockReceive));
                createDefinition(typeof(WarehouseStockResult));
                createDefinition(typeof(Files));
                createDefinition(typeof(Item));
                createDefinition(typeof(Unit));
                createDefinition(typeof(User));
                createDefinition(typeof(Posts));
                createDefinition(typeof(UpdateChecks));

            }
            catch (Exception e)
            {
                Console.Write("カラム情報の初期化に失敗しました。\n"+e.StackTrace);
                throw e;
            }
        }

        /// <summary>
        /// Typeを解析し、すべてのフィールドをカラム情報として登録します。
        /// </summary>
        /// <param name="type"></param>
        private static void createDefinition(Type type)
        {
            if (getDefinition(type.Name) != null)
            {
                throw new ApplicationException("すでに登録されているDefinitionが生成されました。"+type.Name);
            }

            Definition definition = new Definition(type.Name);
            _definitionMapping.Add(definition.getDefinitionName(), definition);

            foreach (PropertyInfo field in type.GetProperties())
            {
                // カラム名が存在する場合は何もしない
                IColumn column = getColumn(field.Name);
                if (column == null)
                {
                    // カラム名が存在しない場合は新しく追加する
                    column = new Column(field.Name);
                    _columnMapping.Add(column.getName(), column);

                }
                // 定義にカラムを登録します。
                definition.internalAddColumn(column);
            }
        }

        /// <summary>
        /// カラム名に対応するIColumnを取得します。
        /// </summary>
        /// <param name="columnName"></param>
        /// <returns></returns>
        public static IColumn getColumn(string columnName)
        {
            return _columnMapping.ContainsKey(columnName) ? _columnMapping[columnName] : null;
        }

        /// <summary>
        /// definitionNameに対応するIDefinitionインスタンスを取得します。
        /// </summary>
        /// <param name="definitionName"></param>
        /// <returns></returns>
        public static IDefinition getDefinition(string definitionName)
        {
            return _definitionMapping.ContainsKey(definitionName) ? _definitionMapping[definitionName] : null;
        }


        /// <summary>
        /// columnが定義に存在するかを判定します。
        /// 存在しない場合は、実装ミスのため非検査例外を投げます。
        /// </summary>
        /// <param name="column"></param>
        public static void checkExistColumn(string column)
        {
            if (DefinitionManager.getColumn(column) == null)
            {
                string message = "存在しないカラム名です。[" + column + "]\nBeanクラスのフィールド名もしくはcolumnの値が間違っている可能性があります。";
                Console.Write(message);
                throw new ApplicationException(message);
            }
        }
    }
}
